#ifndef GAME_ANIMATION_WATER_SHADER_H
#define GAME_ANIMATION_WATER_SHADER_H
//
// Game Animation.
// Copyright (C) 2007 Department of Computer Science, University of Copenhagen
//
#include <animation/configuration.h>

#include <OpenTissue/gpu/cg/cg_program.h>
#include <OpenTissue/gpu/image/image.h>
#include <OpenTissue/gpu/image/io/image_read.h>
#include <OpenTissue/gpu/image/io/image_write.h>
#include <OpenTissue/gpu/image/image_make_noise.h>
#include <OpenTissue/gpu/texture/texture_texture2D.h>
#include <OpenTissue/gpu/texture/texture_create_texture2D.h>

namespace animation
{

  /**
  * The Water Shader.
  * Sets up rendering before drawing water geometry.
  */
  class WaterShader{

  protected:
    OpenTissue::cg::Program       m_vertex_program;
    OpenTissue::cg::Program       m_fragment_program;
  public:
	  typedef OpenTissue::image::Image<unsigned char> image_type;
	  typedef boost::shared_ptr<image_type> image_pointer;
	  image_pointer                          m_reflect_image;
	  OpenTissue::texture::texture2D_pointer m_reflect_texture;
	  image_pointer                          m_bottom_image;
	  OpenTissue::texture::texture2D_pointer m_bottom_texture;
	  image_pointer                          m_noise_image;
	  OpenTissue::texture::texture2D_pointer m_noise_texture;
	void create_textures(){
		if(!m_reflect_image){
			GLint width=512;
			GLint height=512;
			unsigned char*  data=new unsigned char[4*height*width];
			m_reflect_image.reset( new image_type (width ,height,4,data) );
			m_reflect_texture = m_reflect_image->create_texture(GL_RGBA);  
			delete[] data;

			unsigned char*  data2=new unsigned char[4*height*width];
			m_bottom_image.reset( new image_type (width ,height,4,data2) );
			m_bottom_texture = m_bottom_image->create_texture(GL_RGBA);  
			delete[] data2;

			m_noise_image.reset( new OpenTissue::image::Image<unsigned char>() );
			OpenTissue::image::read(demo_path + "TheSwampThing2008/data/water_noise.png",*m_noise_image);
			m_noise_texture = m_noise_image->create_texture(GL_RGBA);
			m_noise_texture->set_repeating(true);
			m_noise_texture->set_mipmapping(true);
		}
	}
    void pre_render(
		bool reload
		,float light_x,float light_y,float light_z
		,float intensity  
		,float water_level
		,float eye_x,float eye_y,float eye_z
		, float time){
      //--- Load vertex program, note that cg-program path is currently hardcoded, a
      //--- more sensible solution would be
      //---
      //---  std::string filename = get_environment_variable("OPENTISSUE") + .... + "vp_grass.cg";
      //---	  
      if(!m_vertex_program.is_program_loaded()||reload)
        m_vertex_program.load_from_file(OpenTissue::cg::Program::vertex_program,demo_path + "../animation/shader/water/water_vp.cg");

      m_vertex_program.set_modelview_projection_matrix();
	  m_vertex_program.set_modelview_inverse_transpose();
	  m_vertex_program.set_modelview_inverse_matrix();

	  m_vertex_program.set_float_param("light_vec",light_x,light_y,light_z);
	  m_vertex_program.set_float_param("intensity",intensity);
	  m_vertex_program.set_float_param("water_level",water_level);
	  m_vertex_program.set_float_param("max_depth",-.5);
	  m_vertex_program.set_float_param("time",time);
	  m_vertex_program.set_float_param("eye_pos",eye_x,eye_y,eye_z);
      //--- load fragment program
      if(!m_fragment_program.is_program_loaded()||reload)
        m_fragment_program.load_from_file(OpenTissue::cg::Program::fragment_program,demo_path + "../animation/shader/water/water_fp.cg");
      m_fragment_program.set_input_texture("reflect_map",m_reflect_texture);
      m_fragment_program.set_input_texture("bottom_map",m_bottom_texture);
      m_fragment_program.set_input_texture("noise_map",m_noise_texture);
      //--- Setup openGL state
	   glEnable(GL_CULL_FACE);
    }
	void setMatrix(){
		m_vertex_program.set_modelview_projection_matrix();
	}
    void enable(){
		m_vertex_program.enable();
		m_fragment_program.enable();
		glEnable(GL_CULL_FACE);
		glEnable(GL_BLEND);
		glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
    }

    void disable()
    {
		glDisable(GL_CULL_FACE);
		glDisable(GL_BLEND);
		m_vertex_program.disable();
		m_fragment_program.disable();
    }
    void post_render()
    {
      glDisable(GL_CULL_FACE);
	  glDisable(GL_BLEND);
      m_fragment_program.disable();
      m_vertex_program.disable();
    }

  };

} // namespace animation

// GAME_ANIMATION_TERRAIN_SHADER_H
#endif
